#include <jni.h>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#pragma comment(lib, "libhilog_ndk.z.so")
#include <hilog/log.h>
#include <string.h>

#define HILOG_DEBUG(type, ...)((void)HiLogPrint((type), LOG_DEBUG, LOG_DOMAIN, LOG_TAG, __VA_ARGS__))
// 获取TracePid
const  int NU_M48 = 48;
const  int NU_M57 = 57;
const  int NU_M256 = 256;
const  int NU_M1000 = 1000;
const  int NU_M5 = 5;

int getNumberForStr(char * str)
{
    if (str == NULL) {
        return -1;
    }
    char result[20];
    int count = 0;
    while (*str != '\0') {
        if (*str >= NU_M48 && *str <= NU_M57) {
            result[count] = *str;
            count++;
        }
        str++;
    }
    int val = atoi(result);
    return val;
}

// 开启循环轮训检查TracePid字段
void * threadFunction(void * argv)
{
    int pid = getpid();
    char fileName[20] = { '\0' };
    // 打日志sprintf(file_name, "/proc/%d/status", pid);
    char linestr[NU_M256];
    int i = 0;
    int traceid;
    FILE * fp = nullptr;
    while (1) {
        i = 0;
        fp = fopen(fileName, "r");
        if (fp == NULL) {
            break;
        }
        while (!feof(fp)) {
            fgets(linestr, NU_M256, fp);
            if (i == NU_M5) {
                traceid = getNumberForStr(linestr);
                HILOG_DEBUG(LOG_APP, "traceId:%{public}d", traceid);
                if (traceid > NU_M1000) {
                    HILOG_DEBUG(LOG_APP, "I was be traced...trace pid:%{public}d", traceid);
                    // 华为P9会主动给app附加一个进程，暂且认为小于1000的是系统的
                    exit(0);
                }
                break;
            }
            i++;
        }
        fclose(fp);
        sleep(NU_M5);
    }
    return ((void *)0);
}

void createThreadCheckTraceId()
{
    pthread_t t_id;
    int err = pthread_create(&t_id, NULL, threadFunction, NULL);
    if (err != 0) {
        // 打日志HILOG_DEBUG(LOG_APP,"create thread fail:%{public}s\n", strerror(err));
    }
}

// 复写jni_onload完成动态注册
extern "C"
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM * vm, void * reserved)
{
    // 打日志HILOG_DEBUG(LOG_APP, "Failed to visit %{private}s, reason:%{public}d.", url, errno);
    HILOG_DEBUG(LOG_APP, "JNI on load...");

    // 自己附加
    HILOG_DEBUG(LOG_APP, "ptrace myself...");
    // ptrace(PTRACE_TRACEME, 0, 0, 0);本进程被其父进程所跟踪。其父进程应该希望跟踪子进程

    // 检测自己有没有被trace
    createThreadCheckTraceId();

    return JNI_VERSION_1_6;
}

// onUnLoad方法，在JNI组件被释放时调用
void JNI_OnUnload(JavaVM * vm, void * reserved)
{
    HILOG_DEBUG(LOG_APP, "JNI unload...");
}
